package tau.dimes.tasks;

import java.util.Set;
import java.util.TreeSet;
import java.util.concurrent.Callable;
import java.util.concurrent.FutureTask;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;

import tau.dimes.data.Row;
import tau.dimes.data.Table;
import tau.dimes.util.IPHelper;
import tau.dimes.util.ProgressMap;

public class QueryToXmlTask extends FutureTask<QueryToXmlTaskResult>
{	
	private static final int ROWS_TO_QUERY = 50;
	
	public QueryToXmlTask(final String server, final String query, final int ipColumn,
		final int traceColumn, final int maxRows, final String requestID)
	{
		super(new Callable<QueryToXmlTaskResult>() {
			@Override
			public QueryToXmlTaskResult call() throws Exception
			{
				return queryToXml(server, query, ipColumn, traceColumn, maxRows, requestID);
			}
		});
	}

	private static QueryToXmlTaskResult queryToXml(String server, String query, int ipColumn, int traceColumn,
		int maxRows, String requestID) throws Exception
	{
		DocumentBuilder db = DocumentBuilderFactory.newInstance().newDocumentBuilder();
		Document doc = db.newDocument();

		Node traceDataNode = doc.createElement("TraceData");
		doc.appendChild(traceDataNode);

		Node hopsNode = doc.createElement("Hops");
		traceDataNode.appendChild(hopsNode);

		Node tracesNode = doc.createElement("Traces");
		traceDataNode.appendChild(tracesNode);

		int rowCount = 0;
		Set<String> hopIDs = new TreeSet<String>();
		String lastTraceID = null;
		Element traceElement = null;
		Element edgeElement = null;

		while (rowCount < maxRows)
		{
			int rows = Math.min(maxRows - rowCount, ROWS_TO_QUERY);
			LoadTableTask loadTable = new LoadTableTask(server, query, rowCount, rows);
			loadTable.run();
			Table table = loadTable.get();
			
			if (table.rows().size() == 0)
				break;

			TranslateIpGeoTask translateIpGeo = new TranslateIpGeoTask(table, ipColumn);
			translateIpGeo.run();
			translateIpGeo.get();

			int latitudeColumn = table.getColumnIndexByName(TranslateIpGeoTask.LATITUDE_COLUMN);
			int longitudeColumn = table.getColumnIndexByName(TranslateIpGeoTask.LONGITUDE_COLUMN);

			for (Row row : table.rows())
			{
				String hopID = IPHelper.toCanonicalString(row.get(ipColumn));
				if (!hopIDs.contains(hopID))
				{
					Element hopElement = doc.createElement("Hop");
					hopElement.setAttribute("ID", hopID);
					hopElement.setAttribute("lat", row.get(latitudeColumn));
					hopElement.setAttribute("long", row.get(longitudeColumn));
					hopsNode.appendChild(hopElement);
					hopIDs.add(hopID);
				}
				
				String traceID = row.get(traceColumn);
				if (lastTraceID == null || !lastTraceID.equals(traceID))
				{
					lastTraceID = traceID;
					traceElement = doc.createElement("Trace");
					tracesNode.appendChild(traceElement);
					edgeElement = null;
				}
				
				if (edgeElement == null)
				{
					edgeElement = doc.createElement("Edge");
					edgeElement.setAttribute("source", hopID);
				}
				else
				{
					edgeElement.setAttribute("dest", hopID);
					traceElement.appendChild(edgeElement);
					edgeElement = doc.createElement("Edge");
				}
				
				rowCount++;
			}
			
			ProgressMap.set(requestID, (rowCount * 100) / maxRows);
		}

		return new QueryToXmlTaskResult(doc, rowCount);
	}
}
